﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.SessionState;
using System.Web.UI.WebControls;
using Inkubator.Wizard.Model.ConditionalMode;
using Inkubator.Wizard.WebWizard.WizardUtilities;

namespace Inkubator.Wizard.WebWizard.WizardControl
{
    /// <summary>
    /// This class represent the Wizard Control to be placed in the Web Page.
    /// </summary>
    public class WizardWeb : Panel
    {
        private bool actionAtEnd;

        private Panel LeftPanel;
        private Panel ContentPanel;
        private Panel ButtonPanel;
        private Panel TitlePanel;
        private Panel CentralPanel;
        private TableCell cellLeft;
        private TableCell cellCenter;

        private Button btnPrevious;
        private Button btnNext;
        private Button btnFinish;

        private HttpSessionState session;
        private List<StepWizard> Steps;
        private int activeStep;
        private ConditionalProgress conditional;
        private StepProgress progress;
        private ActionWizard postAction;
        private List<object[]> answers;

        public WizardWeb()
        {
            actionAtEnd = false;

            //Initialize components
            this.LeftPanel = new Panel();
            this.ButtonPanel = new Panel();
            this.CentralPanel = new Panel();
            this.TitlePanel = new Panel();
            this.ContentPanel = new Panel();
            this.conditional = new ConditionalProgress();

            this.Steps = new List<StepWizard>();

            //Initialize Button Panel
            this.initButtonPanel();

            //Add Panels to Wizard Control
            Table table = new Table();
            TableRow rowCenter = new TableRow();
            cellLeft = new TableCell();
            cellLeft.Controls.Add(this.LeftPanel);
            rowCenter.Cells.Add(cellLeft);
            cellCenter = new TableCell();
            cellCenter.Controls.Add(this.ContentPanel);
            rowCenter.Cells.Add(cellCenter);
            table.Rows.Add(rowCenter);
            table.DataBind();
            this.CentralPanel.Controls.Add(table);

            this.Controls.Add(this.TitlePanel);
            this.Controls.Add(this.CentralPanel);
            this.Controls.Add(this.ButtonPanel);
        }

        /// <summary>
        /// Initialize the Button Panel
        /// </summary>
        private void initButtonPanel()
        {
            this.btnFinish = new Button();
            this.btnNext = new Button();
            this.btnPrevious = new Button();
            this.btnPrevious.Text = "< Previous";
            this.btnNext.Text = "Next >";
            this.btnFinish.Text = "Finish";

            //Setting buttons Events
            this.btnNext.Click += this.btnNext_Click;
            this.btnPrevious.Click += this.btnPrevious_Click;
            this.btnFinish.Click += this.btnFinish_Click;

            this.ButtonPanel.Controls.Add(btnPrevious);
            this.ButtonPanel.Controls.Add(btnNext);
            this.ButtonPanel.Controls.Add(btnFinish);
            this.ButtonPanel.HorizontalAlign = HorizontalAlign.Right;
            this.btnPrevious.Visible = false;
            this.btnFinish.Visible = false;
            this.btnNext.Visible = false;
        }

        /// <summary>
        /// Set the Text to be shown in the Title Panel.
        /// </summary>
        /// <param name="title"></param>
        public void setWizardTitle(string title)
        {
            Label LblTitle = new Label();
            LblTitle.Text = title;

            this.TitlePanel.Controls.Add(LblTitle);
        }

        /// <summary>
        /// Add a step to the Wizard Control.
        /// </summary>
        /// <param name="step"></param>
        public void addStep(StepWizard step)
        {
            this.Steps.Add(step);
        }

        /// <summary>
        /// Load next Step.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnNext_Click(object sender, EventArgs e)
        {
            //Change visible step
            if (activeStep < this.Steps.Count)
            {
                this.Steps.ElementAt(activeStep).Visible = false;

                if (!this.actionAtEnd && this.Steps.ElementAt(activeStep).hasAction())
                {
                    this.Steps.ElementAt(activeStep).executeAction(this.obtainStepResults(this.Steps.ElementAt(activeStep)));
                }

                this.session.Add(((int)session[1]).ToString(), activeStep);
                this.session.Add("previous", (((int)session[1]) + 1));
                activeStep = conditional.analyzeConditions(activeStep, progress, this);
                this.changeSessionValue();
                this.Steps.ElementAt(activeStep).Visible = true;
                this.btnPrevious.Visible = true;
                this.setLeftPanelTitle();
            }
            //Add finish button if it is necessary
            if (activeStep == (this.Steps.Count - 1))
            {
                this.btnFinish.Visible = true;
                this.btnNext.Visible = false;
            }
        }

        /// <summary>
        /// Load the previous Step.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnPrevious_Click(object sender, EventArgs e)
        {
            //Change visible step
            if (activeStep > 0)
            {
                this.Steps.ElementAt(activeStep).Visible = false;

                if (!this.actionAtEnd && this.Steps.ElementAt(activeStep).hasAction())
                {
                    this.Steps.ElementAt(activeStep).executeAction(this.obtainStepResults(this.Steps.ElementAt(activeStep)));
                }

                this.session.Add("previous", (((int)session[1]) - 1));
                activeStep = ((int)session[((int)session[1])]);
                this.changeSessionValue();
                this.Steps.ElementAt(activeStep).Visible = true;
                this.btnNext.Visible = true;
                this.btnFinish.Visible = false;
                this.setLeftPanelTitle();
            }
            //Hide Previous button
            if (activeStep == 0)
            {
                this.btnPrevious.Visible = false;
            }
        }

        /// <summary>
        /// Collect the user inputs and execute the different actions.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnFinish_Click(object sender, EventArgs e)
        {
            answers = new List<object[]>();
            int i = 0;
            foreach (StepWizard step in this.Steps)
            {
                if (this.actionAtEnd && this.Steps.ElementAt(activeStep).hasAction())
                {
                    step.executeAction(this.obtainStepResults(step));
                }

                answers.Add(this.obtainStepResults(step));
                i++;

            }

            if (this.postAction != null)
            {
                this.executePostAction();
            }

        }

        public void setActiveStep(HttpSessionState sessionState)
        {
            this.session = sessionState;
            this.activeStep = (int)session[0];
        }

        private void changeSessionValue()
        {
            session[0] = this.activeStep;
        }

        /// <summary>
        /// Prepare the Wizard to be displayed on the Web Page.
        /// </summary>
        public void Bind()
        {
            this.ContentPanel.Controls.Clear();
            for (int i = 0; i < this.Steps.Count; i++)
            {
                this.ContentPanel.Controls.Add(this.Steps.ElementAt(i));
                this.Steps.ElementAt(i).Visible = false;
            }
            this.Steps.ElementAt(0).Visible = true;
            if (this.Steps.Count > 1)
            {
                this.btnNext.Visible = true;
            }
            else
            {
                this.btnFinish.Visible = true;
            }
            this.setLeftPanelTitle();
        }

        private void setLeftPanelTitle()
        {
            string name = this.Steps.ElementAt(activeStep).getName();
            this.LeftPanel.Controls.Clear();
            Label lblName = new Label();
            lblName.Text = name;
            this.LeftPanel.Controls.Add(lblName);
        }
        
        /// <summary>
        /// Set the StepProgress object from the Wizard Model to the Wizard Control.
        /// </summary>
        /// <param name="stepProgress"></param>
        public void setStepProgress(StepProgress stepProgress)
        {
            this.progress = stepProgress;
        }

        public TableCell getCellCenter()
        {
            return this.cellCenter;
        }
        public TableCell getCellLeft()
        {
            return this.cellLeft;
        }
        public Panel getTitlePanel()
        {
            return this.TitlePanel;
        }
        public Panel getButtonPanel()
        {
            return this.ButtonPanel;
        }
        public List<StepWizard> getSteps()
        {
            return this.Steps;
        }
        public List<object[]> getAnswers()
        {
            return this.answers;
        }

        public void setActionAtEnd(bool actionAt)
        {
            this.actionAtEnd = actionAt;
        }

        /// <summary>
        /// Return an object array containing the user inputs.
        /// </summary>
        /// <param name="step"></param>
        /// <returns></returns>
        private object[] obtainStepResults(StepWizard step)
        {
            List<WebControl> controls = step.obtainAllControls();
            List<string> idControls = step.getIdControls();

            List<object> results = new List<object>();
            results.Add(idControls.ToArray());
            results.Add(ControlRepresentation.parseControlList(controls));

            return results.ToArray();
        }

        public void setPostAction(string assemblyName, string method, string impInterface)
        {
            this.postAction = new ActionWizard(assemblyName, method, impInterface);
        }

        private void executePostAction()
        {
            this.postAction.execute(answers.ToArray());
        }

    }
}
